#pragma once

#define LIST_COLUMN_MAX_WIDTH	128

#define COLUMN_FILENAME_INDEX	0
#define COLUMN_FILESIZE_INDEX	1
#define COLUMN_FILEID_INDEX		2

#define COLUMN_FILESIZE_WIDTH	80
#define COLUMN_FILEID_WIDTH		80
#define COLUMN_FILENAME_MIN		50

#include <atlctrlx.h>

#include "HttpStreamHandler.h"

using std::map;

//This wrapper class is for dunplicate checking
class CBoolWrapper
{
public:
	bool m_bool;

	CBoolWrapper() : m_bool(false) {}
	operator bool() { return m_bool; }
};

//We Create this class only for forwarding check box command message to list view
//So I really hate UI Programming
class CItemListHeader : public CWindowImpl<CItemListHeader, CHeaderCtrl>
{
public:
	BEGIN_MSG_MAP(CItemListHeader)
		COMMAND_ID_HANDLER(IDC_CHECK_ITEMS_SELALL, OnForwardCheckCommand)
	END_MSG_MAP()

public:
	LRESULT OnForwardCheckCommand(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
	{
		//Send Message to the parent window, that's Listview Window, We donot care about Nofifycode
		::SendMessage(GetParent(), WM_COMMAND, (WPARAM)wID, (LPARAM)hWndCtl);
		return TRUE;
	}
};

class CItemsCheckList : public CCheckListViewCtrl
{
//Type definetion
public:
	typedef struct _ITEM_LIST_DATA {
		wstring wstrFileID;
		wstring wstrFileName;
		wstring wstrFileMBSize;
		FLOAT fFileMBSize;
		string strURLRefer;
		string strSecIP;
	} ITEM_LIST_DATA;

public:
	BEGIN_MSG_MAP(CItemsCheckList)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_RESIZECOLUMN, OnResizeColumn)

		COMMAND_ID_HANDLER(IDC_CHECK_ITEMS_SELALL, OnCheckAllSel)

		CHAIN_MSG_MAP(CCheckListViewCtrl)
	END_MSG_MAP()

public:
	CItemsCheckList()
	{}


public:
	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		//We should resize the column after the list view resize its self
		//Two conditins will cause a resize message
		//1 the resize diag was resized
		//2 user change the width of some header, and cause a horizental srollbar
		//Wether or not, we won't receive the size which diag passed
		//The lparam is alway the size of the client area
		PostMessageW(WM_RESIZECOLUMN, NULL, lParam);

		//Call the default precedure
		bHandled = false;
		return TRUE;
	}

	LRESULT OnResizeColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		//In User Drag Mode, we did not resize the column
		if(_ConfigApp.AppSettings.bIsUserDrag)
		{
			return TRUE;
		}

		int nFileSizeWidth = GetColumnWidth(COLUMN_FILESIZE_INDEX);
		int nFileIDWidth = GetColumnWidth(COLUMN_FILEID_INDEX);
		int nFileNameWidth = GetColumnWidth(COLUMN_FILENAME_INDEX);

		//Get Current Client area width
		int nListWidth = LOWORD(lParam);

		//In auto fit mode, we resize the column to fit the client width
		//Assume wether we should enlarge the filename column width
		int nLeftWidth = 0;
		if((nLeftWidth = nListWidth - nFileSizeWidth - nFileIDWidth) < COLUMN_FILENAME_MIN)
		{
			//Keep the min width of filename column
			SetColumnWidth(COLUMN_FILENAME_INDEX, COLUMN_FILENAME_MIN);
		}
		else
		{
			SetColumnWidth(COLUMN_FILENAME_INDEX, nLeftWidth);
		}

		return TRUE;
	}

	LRESULT OnCheckAllSel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
	{
		//Very Simple, Just Check all or Uncheck all

		if(m_ckCheckItemAll.GetCheck() == BST_CHECKED)
		{
			for(int i = 0; i < GetItemCount(); i++)
				SetCheckState(i, true);
		}
		else
		{
			for(int i = 0; i < GetItemCount(); i++)
				SetCheckState(i, false);			
		}

		return TRUE;
	}

public:

	void AddFileItemHeader()
	{
		WCHAR pwstrColumnHeader[LIST_COLUMN_MAX_WIDTH] = { 0 };

		//Calc the file name column init width
		CRect rcList;
        GetWindowRect(rcList);
		int nListRightPadding = ::GetSystemMetrics(SM_CXEDGE)*2 + ::GetSystemMetrics(SM_CXVSCROLL);
        int nInitFileNameColunmWidth = rcList.Width() - nListRightPadding - COLUMN_FILESIZE_WIDTH - COLUMN_FILEID_WIDTH;

		//Load File Name Column
		::LoadStringW(::GetModuleHandle(NULL), IDS_TA_COLUMN_FILENAME, pwstrColumnHeader, LIST_COLUMN_MAX_WIDTH);
		InsertColumn(COLUMN_FILENAME_INDEX, pwstrColumnHeader, LVCFMT_LEFT, nInitFileNameColunmWidth, -1);

		//Load File size column
		::wmemset(pwstrColumnHeader, 0, LIST_COLUMN_MAX_WIDTH);
		::LoadStringW(::GetModuleHandle(NULL), IDS_TA_COLUMN_FILESIZE, pwstrColumnHeader, LIST_COLUMN_MAX_WIDTH);
		InsertColumn(COLUMN_FILESIZE_INDEX, pwstrColumnHeader, LVCFMT_RIGHT, COLUMN_FILESIZE_WIDTH, -1);

		//Load File Id column
		::wmemset(pwstrColumnHeader, 0, LIST_COLUMN_MAX_WIDTH);
		::LoadStringW(::GetModuleHandle(NULL), IDS_TA_COLUMN_FILEID, pwstrColumnHeader, LIST_COLUMN_MAX_WIDTH);
		InsertColumn(COLUMN_FILEID_INDEX, pwstrColumnHeader, LVCFMT_RIGHT, COLUMN_FILEID_WIDTH, -1);

		//Add A checkbox on the header
		//Get List Header and set the style for hold checkbox
		m_lstHeader.SubclassWindow(GetHeader().m_hWnd);
		m_lstHeader.ModifyStyle(HDS_BUTTONS, WS_CLIPCHILDREN);

		//Create Checkbox On List Header
		m_ckCheckItemAll.Create(m_lstHeader, NULL, NULL, BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 0, IDC_CHECK_ITEMS_SELALL);

		//Move the check box to the list view header
		//And set check box size and pos
		int nCheckCX = ::GetSystemMetrics(SM_CXMENUCHECK) + ::GetSystemMetrics(SM_CXEDGE);
		int nCheckCY = ::GetSystemMetrics(SM_CYMENUCHECK) + ::GetSystemMetrics(SM_CYEDGE);
		//3*SM_CXEDGE is cited here http://msdn.microsoft.com/en-us/library/bb775314%28VS.85%29.aspx
		//We Just want to put the check box align with list items and v center
		//And I really hate these caclation
		CRect rcHeaderRect;
		m_lstHeader.GetWindowRect(&rcHeaderRect);

		int nCheckX = ::GetSystemMetrics(SM_CXEDGE) * 3;
		int nCheckY = (rcHeaderRect.Height() - nCheckCY) / 2;
		m_ckCheckItemAll.MoveWindow(nCheckX, nCheckY, nCheckCX, nCheckCY);
	}

	void AddDownFileItem(UINT uiItemIndex, const ITEM_LIST_DATA& itemData)
	{
		//Add File name item
		AddItem(uiItemIndex, COLUMN_FILENAME_INDEX, itemData.wstrFileName.c_str(), uiItemIndex);

		//Add FileSize item
		AddItem(uiItemIndex, COLUMN_FILESIZE_INDEX, itemData.wstrFileMBSize.c_str());

		//Add FileId item
		AddItem(uiItemIndex, COLUMN_FILEID_INDEX, itemData.wstrFileID.c_str());
	}

	void SetAllItemsChecked()
	{
		//Check all items, cause set check won't fire a command msg, so we have to check it by hand
		m_ckCheckItemAll.SetCheck(true);

		for(int i = 0; i < GetItemCount(); i++)
			SetCheckState(i, true);
	}

public:
	CButton m_ckCheckItemAll;
	CItemListHeader m_lstHeader;
};


class CItemsCheckDiag : public CDialogImpl<CItemsCheckDiag>,
						public CDialogResize<CItemsCheckDiag>
{
public:
	enum { IDD = IDD_ITEMS_SELECT };

	BEGIN_MSG_MAP(CItemsCheckDiag)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)

		COMMAND_ID_HANDLER(IDOK, OnOK)
		COMMAND_ID_HANDLER(IDCANCEL, OnCancel)

		NOTIFY_HANDLER(IDC_ITEMS_LIST, LVN_ITEMCHANGED, OnCheckItem)

		CHAIN_MSG_MAP(CDialogResize<CItemsCheckDiag>)

	END_MSG_MAP()

	BEGIN_DLGRESIZE_MAP(CSnifferURLDiag)
		DLGRESIZE_CONTROL(IDOK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(IDCANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
		DLGRESIZE_CONTROL(IDC_STATIC_ITEMS_STATUS, DLSZ_MOVE_Y)

		DLGRESIZE_CONTROL(IDC_ITEMS_LIST, DLSZ_SIZE_X | DLSZ_SIZE_Y)
		DLGRESIZE_CONTROL(IDC_STATIC_ITEMS_SELECTED, DLSZ_SIZE_X | DLSZ_MOVE_Y)
	END_DLGRESIZE_MAP()

public:
	
	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

	LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
	LRESULT OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);

	LRESULT OnCheckItem(int idCtrl, LPNMHDR lpmhr, BOOL& bHandled);

public:
	CItemsCheckDiag();
	~CItemsCheckDiag();
	void CloseDialog(int nVal);
	void CreateItemsList(map<string, vector<CHttpStreamHandler::JSItem>>& pmapItems, map<string, string>& mapSecIps);
	void CreateItemIconList();
	void AddItemsToList();

public:

	CItemsCheckList m_lstItemsList;
	vector<CItemsCheckList::ITEM_LIST_DATA> m_vecItemList;
	vector<CItemsCheckList::ITEM_LIST_DATA> m_vecSelectedItemList;

	CImageList m_imglstFileTypeIcon;
	CStatic m_stcSelectedInfo;

	WCHAR* m_pwstrInfoFormat;
	WCHAR* m_pwstrInfoBuffer;
	
	UINT m_uiCheckedItems;
	FLOAT m_fCheckeFileSize;
};
